﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using KDG.FoldersSize.Properties;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Drawing.Drawing2D;
using KDG.Sys;
using KDG.Sys.Windows;

namespace KDG.FoldersSize
{
    public partial class FormMain : Form
    {
        string _path = string.Empty;
        static int _maxChartSeries = 50;
        //----------------------------------------------------------------------
        // Classes
        //----------------------------------------------------------------------
        class comparer : IComparer<FolderListItem>
        {
            #region IComparer<long> Members

            public int Compare(FolderListItem x, FolderListItem y)
            {
                if (x.Lenght == y.Lenght)
                    return 0;
                if (x.Lenght > y.Lenght)
                    return -1;
                else
                    return 1;
            }

            #endregion
        }
        class FolderListItem
        {
            public string Name;
            public string FullPath;
            public long Lenght;
            public DirInfo DirInfo;
            public bool IsFolder;
            public long? Folders;
            public long? Files;
            public double Progress;

            public FolderListItem(string Name, string FullPath, long Lenght, DirInfo DirInfo, bool IsFolder, long Folders, long Files, double Progress)
            {
                this.Name = Name;
                this.FullPath = FullPath;
                this.Lenght = Lenght;
                this.DirInfo = DirInfo;
                this.IsFolder = IsFolder;
                this.Folders = Folders;
                this.Files = Files;
                this.Progress = Progress;
            }
            public FolderListItem(DirInfo DirInfo)
            {
                this.Name = DirInfo.Name;
                this.FullPath = DirInfo.FullPath;
                this.Lenght = DirInfo.TotalLenght;
                this.DirInfo = DirInfo;
                this.IsFolder = true;
                this.Folders = DirInfo.FoldersCount;
                this.Files = DirInfo.FilesCount;
            }

            public FolderListItem(FileInfo FileInfo)
            {
                this.Name = FileInfo.Name;
                this.FullPath = FileInfo.FullName;
                this.Lenght = FileInfo.Length;
                this.DirInfo = null;
                this.IsFolder = false;
                this.Folders = this.Files = null;
            }
        }

        //----------------------------------------------------------------------
        // Ctors
        //----------------------------------------------------------------------
        public FormMain(string Path)
        {
            _path = Path;
            InitializeComponent();

            cbStartPath.Items.AddRange(Settings.Default.strOldOpenedFolders.ToArray());

            switch (Settings.Default.strFileSizeFormat)
            {
                case "{0}":
                    autoToolStripMenuItem.Checked = true;
                    gBToolStripMenuItem.Checked = false;
                    mBToolStripMenuItem.Checked = false;
                    kBToolStripMenuItem.Checked = false;
                    bToolStripMenuItem.Checked = false;
                    break;
                case "{0:GB}":
                    autoToolStripMenuItem.Checked = false;
                    gBToolStripMenuItem.Checked = true;
                    mBToolStripMenuItem.Checked = false;
                    kBToolStripMenuItem.Checked = false;
                    bToolStripMenuItem.Checked = false;
                    break;
                case "{0:MB}":
                    autoToolStripMenuItem.Checked = false;
                    gBToolStripMenuItem.Checked = false;
                    mBToolStripMenuItem.Checked = true;
                    kBToolStripMenuItem.Checked = false;
                    bToolStripMenuItem.Checked = false;
                    break;
                case "{0:kB}":
                    autoToolStripMenuItem.Checked = false;
                    gBToolStripMenuItem.Checked = false;
                    mBToolStripMenuItem.Checked = false;
                    kBToolStripMenuItem.Checked = true;
                    bToolStripMenuItem.Checked = false;
                    break;
                case "{0:B}":
                    autoToolStripMenuItem.Checked = false;
                    gBToolStripMenuItem.Checked = false;
                    mBToolStripMenuItem.Checked = false;
                    kBToolStripMenuItem.Checked = false;
                    bToolStripMenuItem.Checked = true;
                    break;
                default:
                    autoToolStripMenuItem.Checked = true;
                    gBToolStripMenuItem.Checked = false;
                    mBToolStripMenuItem.Checked = false;
                    kBToolStripMenuItem.Checked = false;
                    bToolStripMenuItem.Checked = false;
                    break;
            }
        }

        //----------------------------------------------------------------------
        // Background worker
        //----------------------------------------------------------------------
        private void driveScan1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            tssScanStatus.Text = (string)e.UserState;
        }
        private void driveScan1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            string findCounts = string.Format(" Find: folders ({0}), files ({1})", driveScan1.DirInfo.FoldersCount, driveScan1.DirInfo.FilesCount);
            if (e.Cancelled)
                tssScanStatus.Text = "Canceled." + findCounts;
            else
            {
                tssScanStatus.Text = "Complete." + findCounts;
                FillTree();
            }
            SetButtons(false);
        }

        //----------------------------------------------------------------------
        // Methods
        //----------------------------------------------------------------------
        private void OpenChildFolder()
        {
            if (foldersList.SelectedItems.Count > 0)
            {
                FolderListItem fli = ((FolderListItem)foldersList.SelectedItems[0].Tag);
                if (fli.IsFolder)
                {
                    string index = foldersList.SelectedItems[0].Text;
                    foreach (TreeNode tn in foldersTree.SelectedNode.Nodes)
                        if (tn.Text == index)
                        {
                            foldersTree.SelectedNode = tn;
                            break;
                        }
                }
            }
        }
        private void RunProgramm()
        {
            if (foldersList.SelectedItems.Count > 0)
            {
                FolderListItem fli = ((FolderListItem)foldersList.SelectedItems[0].Tag);
                Process.Start(fli.FullPath);
            }
        }
        private void FillFolderList(TreeNode treeNode)
        {
            foldersList.Items.Clear();
            int seriesQuantity = 0;

            if (treeNode == null)
                return;

            imagesFoldersList.Images.Clear();
            imagesFoldersList.Images.Add("folder", Resources.iFolder);
            imagesFoldersList.Images.Add("file", Resources.iFile);

            DirInfo dir = (DirInfo)treeNode.Tag;
            List<FolderListItem> list = new List<FolderListItem>();

            foreach (DirInfo di in dir.Folders)
                list.Add(new FolderListItem(di));

            foreach (FileInfo fi in dir.Files)
                list.Add(new FolderListItem(fi));

            list.Sort(new comparer());

            foreach (FolderListItem fli in list)
            {
                double progress = (double)fli.Lenght / (double)dir.TotalLenght * 100.0;
                fli.Progress = progress;

                string imageKey;
                if (Settings.Default.bShowIconsFromExplorer)
                    imageKey = fli.IsFolder ? "folder" : Path.GetExtension(fli.FullPath);
                else
                    imageKey = fli.IsFolder ? "folder" : "file";

                ListViewItem lvi = new ListViewItem(new string[] {
                    fli.Name, 
                    //StrFormatByteSize(fli.Lenght),
                    //fli.Lenght.ToString(new FileSizeFormatProvider()),
                    string.Format(new FileSizeFormatProvider(), Settings.Default.strFileSizeFormat, fli.Lenght),
                    progress.ToString("#0.##"), 
                    fli.Folders.ToString(), 
                    fli.Files.ToString()},
                    imageKey);
                lvi.Tag = fli;

                foldersList.Items.Add(lvi);
                if (!fli.IsFolder)
                    RegisteredDocumentIcon.GetIcon(fli.FullPath);

            }


            foreach (KeyValuePair<string, Bitmap> kvp in RegisteredDocumentIcon.IconHash)
                imagesFoldersList.Images.Add(kvp.Key, kvp.Value);

            double totalProgress = 0.0;
            foreach (ListViewItem lvi in foldersList.Items)
            {
                if (totalProgress > 70.0)
                    break;
                //if (((FolderListItem)lvi.Tag).Progress < 70.0)
                //    break;
                lvi.Font = new Font(lvi.Font, lvi.Font.Style | FontStyle.Bold);
                foreach (global::System.Windows.Forms.ListViewItem.ListViewSubItem lvsi in lvi.SubItems)
                    lvsi.Font = lvi.Font;

                totalProgress += ((FolderListItem)lvi.Tag).Progress;
            }

            tssTotalLenth.Text = string.Format(new FileSizeFormatProvider(), "{0:fs}", dir.TotalLenght);
            tssFolders.Text = dir.FoldersCount.ToString();
            tssFiles.Text = dir.FilesCount.ToString();
        }
        private void FillTree()
        {
            TreeNode root = new TreeNode(driveScan1.Folder);
            root.Tag = driveScan1.DirInfo;
            foldersTree.Nodes.Add(root);

            FillNode(driveScan1.DirInfo, root);

            foldersTree.SelectedNode = root;
            root.Expand();
        }
        private void FillNode(DirInfo dirInfo, TreeNode node)
        {
            foreach (DirInfo di in dirInfo.Folders)
            {
                TreeNode n = new TreeNode(di.Name, 0, 0);
                n.Tag = di;
                node.Nodes.Add(n);
                FillNode(di, n);
            }
        }
        private void SetButtons(bool p)
        {
            btOpen.Enabled = btScan.Enabled = !(btStop.Enabled = p);
        }

        //----------------------------------------------------------------------
        // Handlers
        //----------------------------------------------------------------------
        private void btScan_Click(object sender, EventArgs e)
        {
            driveScan1.Folder = cbStartPath.Text;
            foldersTree.Nodes.Clear();
            foldersList.Items.Clear();
            tssTotalLenth.Text = tssFiles.Text = tssFolders.Text = "";

            SetButtons(true);
            driveScan1.Scan();
        }
        private void folderList_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
        {
            if (e.ColumnIndex != 2)
                e.DrawDefault = true;
            else
            {
                double width;
                string str = e.Item.SubItems[2].Text;
                if (double.TryParse(str, out width))
                {
                    Rectangle rect = e.Bounds;
                    rect.Width = (int)(width / 100.0 * rect.Width);

                    if (rect.Width > 0 && rect.Height > 0)
                    {
                        Brush br = new LinearGradientBrush(rect,
                            Settings.Default.colIndicatorFrom,
                            Settings.Default.colIndicatorTo,
                            LinearGradientMode.Horizontal);
                        e.Graphics.FillRectangle(br, rect);
                    }
                    e.Graphics.DrawRectangle(Pens.DarkGray, rect);
                    if (e.Bounds.Width > 1)
                    {
                        rect.Width = e.Bounds.Width - 1;
                        e.Graphics.DrawRectangle(Pens.LightGray, rect);
                    }
                }

                e.DrawText();
            }
        }
        private void folderList_DrawItem(object sender, DrawListViewItemEventArgs e)
        {
            //e.DrawDefault = true;
            //e.DrawBackground();
            //e.DrawText();
        }
        private void folderList_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
        {
            e.DrawDefault = true;
        }
        private void btOpen_Click(object sender, EventArgs e)
        {
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                cbStartPath.Text = folderBrowserDialog1.SelectedPath;

                if (!cbStartPath.Items.Contains(folderBrowserDialog1.SelectedPath))
                    cbStartPath.Items.Add(folderBrowserDialog1.SelectedPath);
                if (cbStartPath.Items.Count > Settings.Default.iMaxStoredPath)
                    cbStartPath.Items.RemoveAt(cbStartPath.Items.Count - 1);
            }
        }
        private void foldersList_DoubleClick(object sender, EventArgs e)
        {
            if (Control.ModifierKeys == Keys.Control)
                RunProgramm();
            else
                OpenChildFolder();
        }
        private void FormMain_FormClosed(object sender, FormClosedEventArgs e)
        {
            Settings.Default.strLastOpenedFolder = cbStartPath.Text;
            Settings.Default.mainWindowState = this.WindowState;

            Settings.Default.strOldOpenedFolders.Clear();
            Settings.Default.strOldOpenedFolders.AddRange(cbStartPath.Items);
        }
        private void foldersTree_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (e.Node == foldersTree.Nodes[0])
                btFolderUp.Enabled = false;
            else
                btFolderUp.Enabled = true;
            FillFolderList(e.Node);
        }
        private void btStop_Click(object sender, EventArgs e)
        {
            driveScan1.Cancel();

        }

        //----------------------------------------------------------------------
        // Menu items handlers
        //----------------------------------------------------------------------
        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenChildFolder();
        }
        private void openInExplorerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RunProgramm();
        }
        private void autoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Settings.Default.strFileSizeFormat = "{0}";

            autoToolStripMenuItem.Checked = true;
            gBToolStripMenuItem.Checked = false;
            mBToolStripMenuItem.Checked = false;
            kBToolStripMenuItem.Checked = false;
            bToolStripMenuItem.Checked = false;

            FillFolderList(foldersTree.SelectedNode);
        }
        private void gBToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Settings.Default.strFileSizeFormat = "{0:GB}";

            autoToolStripMenuItem.Checked = false;
            gBToolStripMenuItem.Checked = true;
            mBToolStripMenuItem.Checked = false;
            kBToolStripMenuItem.Checked = false;
            bToolStripMenuItem.Checked = false;

            FillFolderList(foldersTree.SelectedNode);
        }
        private void mBToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Settings.Default.strFileSizeFormat = "{0:MB}";

            autoToolStripMenuItem.Checked = false;
            gBToolStripMenuItem.Checked = false;
            mBToolStripMenuItem.Checked = true;
            kBToolStripMenuItem.Checked = false;
            bToolStripMenuItem.Checked = false;

            FillFolderList(foldersTree.SelectedNode);
        }
        private void kBToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Settings.Default.strFileSizeFormat = "{0:kB}";

            autoToolStripMenuItem.Checked = false;
            gBToolStripMenuItem.Checked = false;
            mBToolStripMenuItem.Checked = false;
            kBToolStripMenuItem.Checked = true;
            bToolStripMenuItem.Checked = false;

            FillFolderList(foldersTree.SelectedNode);
        }
        private void bToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Settings.Default.strFileSizeFormat = "{0:B}";

            autoToolStripMenuItem.Checked = false;
            gBToolStripMenuItem.Checked = false;
            mBToolStripMenuItem.Checked = false;
            kBToolStripMenuItem.Checked = false;
            bToolStripMenuItem.Checked = true;

            FillFolderList(foldersTree.SelectedNode);
        }

        //----------------------------------------------------------------------
        // Button handlers
        //----------------------------------------------------------------------
        private void btAbout_Click(object sender, EventArgs e)
        {
            new AboutBox().ShowDialog();
        }
        private void btFolderUp_Click(object sender, EventArgs e)
        {
            if (foldersTree.SelectedNode != null)
                foldersTree.SelectedNode = foldersTree.SelectedNode.Parent;
        }
        private void tbProperties_Click(object sender, EventArgs e)
        {
            new FormProperties().ShowDialog();

            FillFolderList(foldersTree.SelectedNode);
        }

        //----------------------------------------------------------------------
        // Extern methods
        //----------------------------------------------------------------------
        [DllImport("Shlwapi.dll", CharSet = CharSet.Auto)]
        public static extern long StrFormatByteSize(long fileSize,
        [MarshalAs(UnmanagedType.LPTStr)] StringBuilder buffer, int bufferSize);
        public static string StrFormatByteSize(long fileSize)
        {
            StringBuilder sbBuffer = new StringBuilder(100);
            StrFormatByteSize(fileSize, sbBuffer, 100);
            return sbBuffer.ToString();
        }

        private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {

                if (foldersList.SelectedItems.Count > 0)
                {
                    FolderListItem fli = ((FolderListItem)foldersList.SelectedItems[0].Tag);
                    FileInfo fi = new FileInfo(fli.FullPath);
                    if (fi.Exists)
                    {
                        fi.Delete();
                        btScan_Click(this, null);
                    }
                    else
                    {
                        DirectoryInfo di = new DirectoryInfo(fli.FullPath);
                        if (di.Exists)
                        {
                            di.Delete(true);
                            btScan_Click(this, null);
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        private void FormMain_Load(object sender, EventArgs e)
        {
            if (!string.IsNullOrEmpty(_path))
            {
                cbStartPath.Text = _path;
                btScan_Click(this, null);
            }
        }
    }
}
